using System;
using System.IO;
using lucere.exception;
using lucere.io;
using lucere.io.concurrency;
using lucere.test.io.mock;
using lucere.test.util;
using MbUnit.Framework;

namespace lucere.test.io.concurrency
{
	[TestFixture]
	public class LockFactoryTest
	{
		private string TEMP_DIR = Environment.GetEnvironmentVariable("TMP");
		// Verify: default LockFactory has no prefix (ie
		// write.lock is stored in index):
		[Test]
		public void default_FSLockFactory_prefix_should_be_null()
		{
			// Make sure we get null prefix:
			IDirectory dir = new FSDirectoryMock(new SimpleFSLockFactory());
			string prefix = dir.LockFactory.LockPrefix;
			Assert.IsNull(prefix, "Default lock prefix should be null");
		}

		// Verify: NativeFSLockFactory assigns null as lockPrefix if the lockDir is inside directory
		[Test]
		public void native_FSLockFactory_prefix_should_be_not_null()
		{
			var fdir1 = TestUtil.GetTempDir("TestLockFactory.8");
			var fdir2 = TestUtil.GetTempDir("TestLockFactory.8.Lockdir");
			IDirectory dir1 = new FSDirectoryMock(new NativeFSLockFactory(fdir1));
			// same directory, but locks are stored somewhere else. The prefix of the lock factory should != null
			IDirectory dir2 = new FSDirectoryMock(new NativeFSLockFactory(fdir2));

			var prefix1 = dir1.LockFactory.LockPrefix;
			Assert.IsNull(prefix1, "Lock prefix for lockDir same as directory should be null");

			string prefix2 = dir2.LockFactory.LockPrefix;
			Assert.IsNotNull(prefix2, "Lock prefix for lockDir outside of directory should be not null");

			TestUtil.RemoveDir(fdir1);
			TestUtil.RemoveDir(fdir2);
		}

		[Test]
		public void NativeFSLock_can_release_by_other_lock()
		{
			var f = new NativeFSLockFactory(Environment.GetEnvironmentVariable("TMP"));
			f.LockPrefix = "test";
			var l = f.MakeLock("commit");
			var l2 = f.MakeLock("commit");

			Assert.IsTrue(l.Obtain(), "failed to obtain lock");
			try
			{
				Assert.IsTrue(l2.IsLocked());
				l2.Release();
				Assert.Fail("should not have reached here. LockReleaseFailedException should have been thrown");
			}
			catch (LockReleaseFailedException e)
			{
				// expected
			}
			finally
			{
				l.Release();
			}
		}

		// Verify: NativeFSLockFactory works correctly if the lock file exists
		[Test]
		public void testNativeFSLockFactoryLockExists()
		{

			var lockFile = new FileInfo(Path.Combine(TEMP_DIR, "test.lock"));
			if (lockFile.Exists)
			{
				lockFile.Delete();
			}
			//File.Create(lockFile.FullName).Dispose();
			lockFile.Create().Dispose();

			ILock l = new NativeFSLockFactory(TEMP_DIR).MakeLock("test.lock");
			Assert.IsTrue(l.Obtain(), "failed to obtain lock");
			l.Release();
			Assert.IsFalse(l.IsLocked(), "failed to release lock");

		}
	}
}